﻿// <copyright file="_DIRECTORY_STRUCT_SECONDARY.cs" company="Sinclair Community College">
// Copyright 2010 Sinclair Community College
// </copyright>
// <originalAuthor>Patrick S. Seymour (patrick.seymour@gmail.com)</originalAuthor>

namespace SinclairCC.AppV
{
    using System;

    /// <summary>
    /// This structure contains the metadata of a file or a directory.
    /// </summary>
    /// <remarks>
    /// This structure is just a shorter version of the _DIRECTORY_STRUCT_PRIMARY structure.
    /// This structure is only used if the structure type is LINK_DATA. 
    /// </remarks>
    public class _DIRECTORY_STRUCT_SECONDARY
    {
        private StructureTypeId structureType;

        /// <summary>
        /// Total size of this structure.
        /// </summary>
        private uint dirDataLen;

        /// <summary>
        /// The offset of this structure entry within the parent directory entry table (the
        /// children directory structures that reside within a parent).
        /// </summary>
        private uint dirDataOffset;

        /// <summary>
        /// The index of the corresponding container that describes this structure.
        /// </summary>
        private uint containerIndex;

        /// <summary>
        /// The security identifier of the primary group for the file/directory.
        /// </summary>
        /// <remarks>
        /// This is principally for POSIX support, where the group ID is mandatory.
        /// </remarks>
        private uint primaryGroupId;

        /// <summary>
        /// The length of the short file name (in bytes), not including the double byte terminating
        /// NULL character.
        /// </summary>
        private ushort shortNameLength;

        /// <summary>
        /// The length of the long file name (in bytes), not including the double byte terminating
        /// NULL character.
        /// </summary>
        private ushort fileNameLength;

        /// <summary>
        /// Short file name in WCHAR. This is an array of characters with fixed size 13 (26 bytes).
        /// </summary>
        private string shortName; /* 26 bytes */

        /// <summary>
        /// Long file name in WCHAR.
        /// </summary>
        private string fileName; /* variable */

        public _DIRECTORY_STRUCT_SECONDARY(System.IO.BinaryReader fileReader)
        {
            this.ReadContainer(fileReader);
        }
        
        /// <summary>
        /// Reads the actual data for this container from the file.
        /// </summary>
        protected void ReadContainer(System.IO.BinaryReader fileReader)
        {
            uint rawUInt;

            rawUInt = fileReader.ReadUInt32();

            // TODO: Is this appropriate? Is it true that if the structure type ID is zero, the container is empty?
            if (rawUInt == 0) return;

            if (Enum.IsDefined(typeof(StructureTypeId), rawUInt))
            {
                this.structureType = (StructureTypeId)rawUInt;
            } 
           
            /*
             * 
             * This needs to be fixed to match how _DIRECTORY_STRUCT_PRIMARY does it.
             * 
            */

            this.dirDataLen = fileReader.ReadUInt32();
            this.dirDataOffset = fileReader.ReadUInt32();
            this.containerIndex = fileReader.ReadUInt32();
            this.primaryGroupId = fileReader.ReadUInt32();

            this.shortNameLength = fileReader.ReadUInt16();
            this.fileNameLength = fileReader.ReadUInt16();

            byte[] stringBytes;
            System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
            stringBytes = fileReader.ReadBytes(26);
            if (this.shortNameLength <= stringBytes.Length)
            {
                this.shortName = encoding.GetString(stringBytes, 0, (int)this.shortNameLength);
            }

            stringBytes = fileReader.ReadBytes(this.fileNameLength * 2);
            if (this.fileNameLength <= stringBytes.Length)
            {
                this.fileName = encoding.GetString(stringBytes, 0, (int)this.fileNameLength);
            }
        }

        public StructureTypeId StructureType
        {
            get { return this.structureType; }
        }

        public uint DirDataLen
        {
            get { return this.dirDataLen; }
        }

        public uint DirDataOffset
        {
            get { return this.dirDataOffset; }
        }

        public uint ContainerIndex
        {
            get { return this.containerIndex; }
        }

        public uint PrimaryGroupId
        {
            get { return this.primaryGroupId; }
        }

        public string ShortName
        {
            get { return this.shortName; }
        }

        public string LongName
        {
            get { return this.fileName; }
        }
    }
}
